home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Visual Database / Visual dBase Pro v7.0 / DATA1.CAB / Utilities / Upgrade / Qbe2dmd.prg < prev    next >
Encoding:
Text File  |  1997-11-20  |  9.7 KB  |  340 lines

  1. //--------------------------------------------------------------
  2. //
  3. //  qbe2dmd.prg
  4. //
  5. //  This utility can convert a Visual dBASE 5.x query to 
  6. //  a Visual dBASE 7 data module. You can call it as a 
  7. //  function with 2 optional parameters. If you call it with 
  8. //  no parameters, a dialog opens for selecting the query
  9. //  to convert. The function returns true if it creates a 
  10. //  data module file without error.
  11. //
  12. //  Syntax:
  13. //
  14. //      qbe2dmd( [<expC: Query file name>] [,<expL: overwrite] )
  15. //
  16. //  Example: To create orders.dmd from orders.qbe and 
  17. //           overwrite an existing orders.dmd without 
  18. //           confirmation.
  19. //  
  20. //      qbe2dmd( "orders.qbe", true )
  21. //
  22. //  Dependencies:
  23. //
  24. //      none
  25. //
  26. //  Visual dBASE Samples Group
  27. //
  28. //  $Revision:   1.1  $
  29. //
  30. //  Copyright (c) 1997, Borland International, Inc. 
  31. //  All rights reserved.
  32. //
  33. //---------------------------------------------------------------//
  34. // 
  35.  
  36. function qbe2dmd( sQbe, bOverwrite )          
  37.    // Call create data module function if data module and 
  38.    // QBE file names are valid.
  39.    local   bOK, sDmd
  40.    private prQbe
  41.    private prOverwrite
  42.  
  43.    bOK         = false
  44.    prQbe       = sQbe
  45.    prOverwrite = bOverwrite
  46.  
  47.    if ( PCOUNT() == 0 OR TYPE( "prQbe" ) <> "C" )
  48.       sQbe = UPPER( GETFILE("*.QBE", ;
  49.                             "Convert Query to Data Module", ;
  50.                              true,false) )
  51.    else
  52.       sQbe = UPPER( sQbe )
  53.    endif
  54.  
  55.    if ( PCOUNT()  < 2 OR TYPE( "prOverwrite" ) <> "L" )
  56.       bOverwrite = false
  57.    endif
  58.  
  59.    if ( FILE( sQbe ) AND ( RIGHT( sQbe, 4 ) == ".QBE") )
  60.       sDmd = SUBSTR( sQbe, 1, LEN( sQbe ) - 3 ) + "DMD"
  61.  
  62.       if ( FILE( sDmd ) AND ( NOT bOverwrite ) )
  63.          bOK = ( MSGBOX( sDmd + ;
  64.                    " already exists. Overwrite it?", ;
  65.                    "Already Exists", ;
  66.                    4 + 32) == 6 )
  67.       else
  68.          bOK = true
  69.       endif
  70.  
  71.       if ( bOK )
  72.          bOK = createDmd( sQbe, sDmd, true )
  73.       endif
  74.  
  75.    endif
  76.  
  77. return ( bOK )
  78.  
  79.  
  80.  
  81. function createDmd( sQbe, sDmd, bSession )
  82.    // create a data module from a query
  83.    local fDmd, sPath, sName, sDatabase, sPrimary, aTable, aRel, nTop, oNamer, aProp, aAlias, n1
  84.  
  85.    create session
  86.    set exact off
  87.    set fullpath on
  88.    set space on
  89.  
  90.    // Switch to .QBE directory
  91.    sPath = extractPath( sQbe )
  92.    if not empty( sPath )
  93.      set directory to ( sPath )
  94.    endif
  95.  
  96.    try
  97.       set view to ( sQbe )
  98.    catch ( Exception e )
  99.       msgbox( e.message, "Cannot open QBE", 16 )
  100.       return false
  101.    endtry
  102.  
  103.    // Extract file name from full path and extension, and convert to proper case
  104.    sName = proper( extractFileName( sDmd ) )
  105.  
  106.    // See if database is open
  107.    sDatabase = database()
  108.  
  109.    // Get primary work area of QBE
  110.    sPrimary = alias()
  111.  
  112.    // Find all open tables
  113.    aTable = new Array()
  114.    for n1 = 1 to 225
  115.       select ( n1 )
  116.       if not empty( alias() )
  117.          aTable.add( alias() )
  118.       endif
  119.    endfor
  120.  
  121.    if aTable.size == 0
  122.       msgbox( "No tables opened by QBE", "Nothing to do", 48 )
  123.       return false
  124.    endif
  125.  
  126.    // Sort related tables and get list of relations
  127.    aRel = sortRelatedTables( aTable )
  128.  
  129.    // Initialize name mangler
  130.    oNamer = new NameMangler()
  131.    oNamer.add( "className", "rowset" )
  132.  
  133.    fDmd = new DesignerFile()
  134.    fDmd.create( sDmd )
  135.    fDmd.writeEndHeader()
  136.    fDmd.writeClassLine( sName + "DataModule", "DATAMODULE" )
  137.  
  138.    nTop  = 0
  139.  
  140.    if bSession
  141.       // Use Session object if specified
  142.       aProp = { { "top", nTop } }
  143.       fDmd.writeComponent( "SESSION1", "Session", aProp, true )
  144.       oNamer.add( "SESSION1" )
  145.    endif
  146.  
  147.    // Create macro-commands
  148.    #define APROP_NEW     nTop += 2; aProp = { { "top", nTop } }
  149.    #define APROP_SESSION if bSession; aProp.add( { "session", "parent.SESSION1" } ) ; endif
  150.    #define APROP_ACTIVE  aProp.add( { "active", "true" } )
  151.  
  152.    // Stream database if necessary
  153.    if not empty( sDatabase )
  154.       APROP_NEW
  155.       APROP_SESSION
  156.       aProp.add( { "databaseName", ["] + sDatabase + ["] } )
  157.       APROP_ACTIVE
  158.       sDatabase := oNamer.safeName( sDatabase, true )
  159.       fDmd.writeComponent( sDatabase, "Database", aProp, true )
  160.    endif
  161.  
  162.    aAlias = new AssocArray()
  163.    // Stream each table as a query
  164.    for n1 = 1 to aTable.size
  165.       select ( aTable[ n1 ] )
  166.       APROP_NEW
  167.       APROP_SESSION
  168.       if not empty( sDatabase )
  169.          aProp.add( { "database", "parent." + sDatabase } )
  170.       endif
  171.       if empty( sDatabase )
  172.             aProp.add( { "sql", ['select * from "] + dbf() + ["'] } )
  173.       else
  174.             aProp.add( { "sql", ['select * from ] + extractFileName( dbf() ) + ['] } )
  175.       endif
  176.       APROP_ACTIVE
  177.       aAlias[ alias() ] = oNamer.safeName( alias(), true )
  178.       fDmd.writeComponent( aAlias[ alias() ], "Query", aProp, true )
  179.  
  180.       // Rowset properties
  181.       aProp = new Array()
  182.       if not empty( order() )
  183.          aProp.add( { "indexName", ["] + order() + ["] } )
  184.       endif
  185.       if aRel.isKey( alias() )
  186.          aProp.add( { "masterRowset", "parent.parent." + aAlias[ aRel[ alias() ][ 1 ] ] + ".rowset" } )
  187.          aProp.add( { "masterFields", ["] + aRel[ alias() ][ 2 ] + ["] } )
  188.       endif
  189.       if aProp.size > 0
  190.          fDmd.writeWith( "this." + aAlias[ alias() ] + ".rowset", aProp )
  191.       endif
  192.    endfor
  193.  
  194.    // Assign primary rowset
  195.    if not empty( sPrimary )
  196.      fDmd.writeAssign( "this.rowset", "this." + aAlias[ sPrimary ] + ".rowset" )
  197.    endif
  198.  
  199.    fDmd.writeEndClass()   
  200.    fDmd.close()
  201.  
  202. return FILE( sDmd )
  203.  
  204.  
  205.  
  206. function extractFileName( sPath )
  207. return sPath.substring( max( rat( "\", sPath ), rat( ":", sPath ) ), sPath.lastIndexOf( "." ) )
  208.  
  209.  
  210. function extractPath( sPath )
  211. return sPath.left( max( rat( "\", sPath ), rat( ":", sPath ) ) )
  212.  
  213.  
  214.  
  215. function sortRelatedTables( aTable )
  216.    // Make sure related tables are in the proper order (child tables open last)
  217.    // and return relation information for each child table
  218.    local aRel, nTable, nTarget, cTarget, nElem
  219.    aRel = new AssocArray()
  220.    nTable = 1
  221.  
  222.    do while nTable <= aTable.size
  223.       select ( aTable[ nTable ] )         // Go to each work area with an open table
  224.       nTarget = 1
  225.  
  226.       do while not empty( target( nTarget ))
  227.          cTarget = target( nTarget )      // If table is related into another work area
  228.  
  229.          if aRel.isKey( cTarget ) and aRel[ cTarget ][ 1 ] # alias()
  230.             ? "WARNING: ", cTarget, "has more than one master. Using", alias()
  231.          endif
  232.          // Store relation information in AssocArray
  233.          aRel[ cTarget ] = { alias(), relation( nTarget ) }
  234.  
  235.          nElem = aTable.scan( cTarget )
  236.          if nElem < nTable                // If target is in an "earlier" work area
  237.             aTable.delete( nElem )        // move it to the end
  238.             aTable[ aTable.size ] := cTarget  
  239.             nTable--                  
  240.          endif
  241.  
  242.          nTarget++
  243.       enddo
  244.  
  245.       nTable++
  246.    enddo
  247.  
  248. return aRel
  249.  
  250.  
  251.  
  252. class DesignerFile of File
  253.  
  254.    function writeEndHeader()
  255.       this.writeln( "** END HEADER -- do not remove this line" )
  256.       this.writeln( "//" )
  257.       this.writeln( "// Generated on " + date() )
  258.       this.writeln( "//" )
  259.  
  260.    function writeClassLine( sName, sSuper, bCustom )
  261.       this.writeln( "class " + sName + " of " + sSuper + iif( bCustom, " custom", "" ) )
  262.       this.writeln( "" )
  263.  
  264.    function writeComponent( sName, sClass, aProps, bParent )
  265.       local nProp
  266.       this.writeln( "   this." + sName + " = new " + sClass + "()" )
  267.       if bParent
  268.          this.writeln( "   this." + sName + ".parent = this" )
  269.       endif
  270.       if aProps.size > 0
  271.          this.writeWith( "this." + sName, aProps )
  272.       else
  273.          this.writeln( "" )
  274.       endif
  275.  
  276.    function writeWith( sName, aProps )
  277.       this.writeln( "   with (" + sName + ")" )
  278.       for nProp = 1 to aProps.size
  279.          this.writeAssign( aProps[ nProp ][ 1 ], aProps[ nProp ][ 2 ], 2 )
  280.       endfor
  281.       this.writeln( "   endwith" )
  282.       this.writeln( "" )
  283.  
  284.    function writeAssign( sProp, sValue, nLevel )
  285.       if argcount() < 3
  286.          nLevel := 1
  287.       endif
  288.       this.writeln( space( 3 * nLevel ) + sProp + " = " + sValue )
  289.  
  290.    function writeEndClass
  291.       this.writeln( "" )
  292.       this.writeln( "endclass" )
  293.  
  294. endclass
  295.  
  296.  
  297.  
  298. class NameMangler
  299.    protect wordList
  300.  
  301.    // Use AssocArray to store words to avoid SET EXACT problems with Array::scan()
  302.    this.wordList = new AssocArray()
  303.   
  304.    function add()
  305.       local nArg
  306.       for nArg = 1 to argcount()
  307.          this.wordList[ upper( argvector( nArg ) ) ] = null
  308.       endfor
  309.  
  310.    function safeName( sArg, bEnum )
  311.       local sRet, sName, nGen
  312.       sName = upper( this.safeChars( sArg ) )
  313.       nGen  = 1
  314.       if bEnum                                   
  315.          sRet = sName + nGen++                   // Use either enumerated name
  316.       else
  317.          sRet = sName                            // or plain name
  318.       endif                                      // first
  319.       do while this.wordList.isKey( sRet )       // If there's a match
  320.          sRet := sName + nGen++                  // tack on the generated number
  321.       enddo                                      // until there is no match
  322.       this.add( sRet )
  323.    return sRet
  324.  
  325.    function safeChars( sArg )
  326.       local sRet, c1, nChar
  327.       sRet = ""
  328.       for nChar = 1 to len( sArg )
  329.          c1 = substr( sArg, nChar, 1 )
  330.          if isalpha( c1 ) or c1 == "_" or c1 $ "0123456789"
  331.             sRet += c1
  332.         endif
  333.       endfor
  334.       if not isalpha( left( sRet, 1 ) )  // If first character is not valid
  335.         sRet = "X" + sRet                // Add default valid character
  336.       endif
  337.    return sRet
  338.  
  339. endclass   
  340.